﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using DALS = Medianamik.Core.DAL.SubSonicDAL;
using System.Collections.ObjectModel;
using System.Globalization;

namespace Medianamik.Core
{
    public class NodePropertyCollection : KeyedCollection<Guid, NodeProperty>
    {
        #region Fields

        /// <summary>
        /// Le NodeInstance propriétaire de la collection
        /// </summary>
        internal NodeInstance NodeInstance
        {
            get;
            private set;
        }

        #endregion

        #region .ctors

        /// <summary>
        /// Créer une instance de la classe, liée à un NodeInstance
        /// </summary>
        /// <param name="pOwner">Le NodeInstance propriétaire de la collection</param>
        public NodePropertyCollection(NodeInstance pOwner, IEnumerable<NodeProperty> pProperties)
            : base(null, 0)
        {
            if (pOwner == null)
            {
                throw new ArgumentNullException("pOwner");
            }

            NodeInstance = pOwner;

            AddRange(pProperties);
        }

        #endregion

        #region Overrides

        protected override void InsertItem(int index, NodeProperty item)
        {
            item.Node = NodeInstance.Node;
            base.InsertItem(index, item);
        }

        protected override void ClearItems()
        {
            foreach (var item in Items)
            {
                item.Node = null;
            }
            base.ClearItems();
        }

        protected override void RemoveItem(int index)
        {
            this[index].Node = null;
            base.RemoveItem(index);
        }

        #endregion

        #region Methods

        public void AddRange(IEnumerable<NodeProperty> items)
        {
            foreach (var item in items)
            {
                item.Node = NodeInstance.Node;
                Add(item);
            }
        }

        public NodeProperty this[string pName]
        {
            get
            {
                NodeProperty property = this.FirstOrDefault(p => p.Name.Equals(pName, StringComparison.OrdinalIgnoreCase));

                if (property == null)
                {
                    throw new CoreException("No property with the name " + pName + " was found");
                }

                return property;
            }
        }

        public bool Exists(string pName)
        {
            return Items.Any(p => p.Name.Equals(pName, StringComparison.OrdinalIgnoreCase));
        }

        public bool Exists(Guid pPropertyId)
        {
            return Items.Any(p => p.NodeTypePropertyID.Equals(pPropertyId));
        }

        public void ForEach(Action<NodeProperty> pAction)
        {
            foreach (var item in Items)
            {
                pAction(item);
            }
        }

        public ReadOnlyNodePropertyCollection AsReadOnly()
        {
            return new ReadOnlyNodePropertyCollection(this);
        }

        protected override Guid GetKeyForItem(NodeProperty item)
        {
            return item.NodeTypePropertyID;
        }

        #endregion
    }

    public class ReadOnlyNodePropertyCollection : IList<NodeProperty>
    {
        #region Fields

        private NodePropertyCollection _list;

        #endregion

        #region .ctors

        internal ReadOnlyNodePropertyCollection(NodePropertyCollection list)
        {
            if (list == null)
            {
                throw new ArgumentNullException("list");
            }
            _list = list;
        }

        #endregion

        #region Properties

        public NodeProperty this[string pName]
        {
            get
            {
                return _list[pName];
            }
        }

        public NodeProperty this[Guid pNodeTypePropertyID]
        {
            get
            {
                return _list[pNodeTypePropertyID];
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Indique si une propriété existe avec le NodeTypePropertyId passé en paramètre
        /// </summary>
        /// <param name="pNodeTypePropertyID"></param>
        /// <returns></returns>
        public bool Exists(Guid pNodeTypePropertyID)
        {
            return _list.Exists(pNodeTypePropertyID);
        }

        public bool Exists(string pName)
        {
            NodeProperty dummy;
            return Exists(pName, out dummy);
        }

        public bool Exists(string pName, out NodeProperty pNodeProperty)
        {
            pNodeProperty = _list.FirstOrDefault(p => p.Name.Equals(pName, StringComparison.InvariantCultureIgnoreCase));

            return pNodeProperty != null;
        }

        public void ForEach(Action<NodeProperty> pAction)
        {
            foreach (var item in _list)
            {
                pAction(item);
            }
        }

        public bool Contains(NodeProperty item)
        {
            return _list.Contains(item);
        }

        public int Count
        {
            get { return _list.Count; }
        }

        public NodeProperty this[int index]
        {
            get
            {
                return _list[index];
            }
        }

        #endregion

        #region IList<NodeProperty> Members

        public int IndexOf(NodeProperty item)
        {
            return _list.IndexOf(item);
        }

        void IList<NodeProperty>.Insert(int index, NodeProperty item)
        {
            throw new NotSupportedException("It's not possible to modify a readonly collection");
        }

        void IList<NodeProperty>.RemoveAt(int index)
        {
            throw new NotSupportedException("It's not possible to modify a readonly collection");
        }

        NodeProperty IList<NodeProperty>.this[int index]
        {
            get
            {
                return _list[index];
            }
            set
            {
                throw new NotSupportedException("It's not possible to modify a readonly collection");
            }
        }

        public IEnumerator<NodeProperty> GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        #endregion

        #region ICollection<NodeProperty> Members

        void ICollection<NodeProperty>.Add(NodeProperty item)
        {
            throw new NotSupportedException("It's not possible to modify a readonly collection");
        }

        void ICollection<NodeProperty>.Clear()
        {
            throw new NotSupportedException("It's not possible to modify a readonly collection");
        }

        bool ICollection<NodeProperty>.Contains(NodeProperty item)
        {
            return _list.Contains(item);
        }

        void ICollection<NodeProperty>.CopyTo(NodeProperty[] array, int arrayIndex)
        {
            _list.CopyTo(array, arrayIndex);
        }

        int ICollection<NodeProperty>.Count
        {
            get { return _list.Count; }
        }

        bool ICollection<NodeProperty>.IsReadOnly
        {
            get { return true; }
        }

        bool ICollection<NodeProperty>.Remove(NodeProperty item)
        {
            throw new NotSupportedException("It's not possible to modify a readonly collection");
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        #endregion

        #region IEnumerable<NodeProperty> Members

        IEnumerator<NodeProperty> IEnumerable<NodeProperty>.GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        #endregion
    }
}
